/**
 * \class CWorkSpaces
 * \brief This is a core class to make spaces efficently used.
 * \version 0.3.3
 *
 * \author Woo-Hyun Kim (woorung@nhncorp.com, woorung@gmail.com)
 * \author http://blog.naver.com/wisereign .
 *
 * \date 2008/8/5
 */
// =============================================================
#include "CWorkSpaces.h"

CWorkSpaces::CWorkSpaces(char *dip, int dport)
{
	host = dip;
	port = dport;

	use_other_topology = false;
	_topology = NULL;

	use_bulk = false;
	space = NULL;
	bulk_space = NULL;

	_service = CUBE_SERVICE_SPACE;

	char random_instance[1024];
	CRandom unique_random;
	sprintf(random_instance, "%lld.%ld", unique_random.millitime(), unique_random.generate());
	_instance = random_instance;

	auto_clean = true;

	success = -1;

	initialize();
}

CWorkSpaces::CWorkSpaces(char *dip, int dport, char *service, char *instance)
{
	host = dip;
	port = dport;

	use_other_topology = false;
	_topology = NULL;

	use_bulk = false;
	space = NULL;
	bulk_space = NULL;

	_service = service;
	_instance = instance;

	auto_clean = true;

	success = -1;

	initialize();
}

CWorkSpaces::CWorkSpaces(CDHT *top)
{
	host = top->get_dip();
	port = top->get_dport();

	use_other_topology = true;
	_topology = top;

	use_bulk = false;
	space = NULL;
	bulk_space = NULL;

	_service = top->get_rtype();

	char random_instance[1024];
	CRandom unique_random;
	sprintf(random_instance, "%lld.%ld", unique_random.millitime(), unique_random.generate());
	_instance = random_instance;

	auto_clean = true;

	success = -1;

	initialize();
}

CWorkSpaces::~CWorkSpaces()
{
	finalize();

	if(use_other_topology==false&&_topology!=NULL) delete _topology;
	if(!use_bulk&&space!=NULL) delete space;
	if(use_bulk&&bulk_space!=NULL) delete bulk_space;
}

void CWorkSpaces::initialize()
{
	if(_topology==NULL) {
		_topology = new CChord((char *)host.c_str(), port);
		success = _topology->configure((char *)_service.c_str());
	}
}

void CWorkSpaces::finalize()
{
	flush();

	if(auto_clean) cleanup();
}

bool CWorkSpaces::alive()
{
	bool _alive = false;

	if(success>0) _alive = true;
	else _alive = false;

	return _alive;
}

void CWorkSpaces::service(char *s)
{
	_service = s;
}

const char *CWorkSpaces::service()
{
	return _service.c_str();
}

void CWorkSpaces::instance(char *i)
{
	_instance = i;
}

const char *CWorkSpaces::instance()
{
	return _instance.c_str();
}

CDHT *CWorkSpaces::topology()
{
	return _topology;
}

int CWorkSpaces::write(string &space_key, pair<string,string> &kv)
{
	if(!use_bulk) {
		if(space==NULL) space = new CSpaceProxy(this);

		return space->write(space_key, kv);
	}
	else {
		if(bulk_space==NULL) bulk_space = new CBulkSpaceProxy(this);

		return bulk_space->write(space_key, kv);
	}
}

int CWorkSpaces::write(pair<string,string> &kv)
{
	if(!use_bulk) {
		if(space==NULL) space = new CSpaceProxy(this);

		return space->write(kv);
	}
	else {
		if(bulk_space==NULL) bulk_space = new CBulkSpaceProxy(this);

		return bulk_space->write(kv);
	}
}

int CWorkSpaces::read(string &space_key, pair<string,string> &kv)
{
	if(!use_bulk) {
		if(space==NULL) space = new CSpaceProxy(this);

		return space->read(space_key, kv);
	}
	else {
		if(bulk_space==NULL) bulk_space = new CBulkSpaceProxy(this);

		return bulk_space->read(space_key, kv);
	}
}

int CWorkSpaces::read(pair<string,string> &kv)
{
	if(!use_bulk) {
		if(space==NULL) space = new CSpaceProxy(this);

		return space->read(kv);
	}
	else {
		if(bulk_space==NULL) bulk_space = new CBulkSpaceProxy(this);

		return bulk_space->read(kv);
	}
}

int CWorkSpaces::readIfExists(string &space_key, pair<string,string> &kv)
{
	if(!use_bulk) {
		if(space==NULL) space = new CSpaceProxy(this);

		return space->readIfExists(space_key, kv);
	}
	else {
		if(bulk_space==NULL) bulk_space = new CBulkSpaceProxy(this);

		return bulk_space->readIfExists(space_key, kv);
	}
}

int CWorkSpaces::readIfExists(pair<string,string> &kv)
{
	if(!use_bulk) {
		if(space==NULL) space = new CSpaceProxy(this);

		return space->readIfExists(kv);
	}
	else {
		if(bulk_space==NULL) bulk_space = new CBulkSpaceProxy(this);

		return bulk_space->readIfExists(kv);
	}
}

int CWorkSpaces::take(string &space_key, pair<string,string> &kv)
{
	if(!use_bulk) {
		if(space==NULL) space = new CSpaceProxy(this);

		return space->take(space_key, kv);
	}
	else {
		if(bulk_space==NULL) bulk_space = new CBulkSpaceProxy(this);

		return bulk_space->take(space_key, kv);
	}
}

int CWorkSpaces::take(pair<string,string> &kv)
{
	if(!use_bulk) {
		if(space==NULL) space = new CSpaceProxy(this);

		return space->take(kv);
	}
	else {
		if(bulk_space==NULL) bulk_space = new CBulkSpaceProxy(this);

		return bulk_space->take(kv);
	}
}

int CWorkSpaces::takeIfExists(string &space_key, pair<string,string> &kv)
{
	if(!use_bulk) {
		if(space==NULL) space = new CSpaceProxy(this);

		return space->takeIfExists(space_key, kv);
	}
	else {
		if(bulk_space==NULL) bulk_space = new CBulkSpaceProxy(this);

		return bulk_space->takeIfExists(space_key, kv);
	}
}

int CWorkSpaces::takeIfExists(pair<string,string> &kv)
{
	if(!use_bulk) {
		if(space==NULL) space = new CSpaceProxy(this);

		return space->takeIfExists(kv);
	}
	else {
		if(bulk_space==NULL) bulk_space = new CBulkSpaceProxy(this);

		return bulk_space->takeIfExists(kv);
	}
}

long CWorkSpaces::size()
{
	string space_key = "";
	return size(space_key);
}

long CWorkSpaces::size(string &space_key)
{
	if(!use_bulk) {
		if(space==NULL) space = new CSpaceProxy(this);

		return space->size(space_key);
	}
	else {
		if(bulk_space==NULL) bulk_space = new CBulkSpaceProxy(this);

		return bulk_space->size(space_key);
	}
}

int CWorkSpaces::bulk(int limit)
{
	use_bulk = true;

	if(bulk_space==NULL) bulk_space = new CBulkSpaceProxy(this);

	return bulk_space->bulk(limit);
}

int CWorkSpaces::flush()
{
	if(!use_bulk) return 1;
	else return bulk_space->flush();
}

void CWorkSpaces::autoclean(bool is_clean)
{
	auto_clean = is_clean;
}

int CWorkSpaces::_clean(CServiceInfo &found_space)
{
	CServiceProxy service_proxy;
	service_proxy.connect(found_space.getIP(), found_space.getPort());

	cube__CService space_service;
	space_service.service(found_space.getName());
	space_service.instance((char *)_instance.c_str());

	int nothing;
	// remove the space service instance
	if(service_proxy.finalize(&space_service, nothing)!=SOAP_OK) {
		soap_print_fault(service_proxy.soap(), stderr);
	}
}

int CWorkSpaces::clean(string &space_key)
{
	// find a specific space responsible for the data key
	CServiceInfo found_space = _topology->lookup((char *) space_key.c_str());

#ifdef DEBUG
	cout << "##################### clean ########################" << endl;
	cout << "service name = " << found_space.getName() << endl;
	cout << "instance name = " << _instance << endl;
	cout << "host ip = " << found_space.getIP() << endl;
	cout << "host port = " << found_space.getPort() << endl;
	cout << "####################################################" << endl;
#endif

	_clean(found_space);
}

int CWorkSpaces::cleanup()
{
	vector<CServiceInfo> allspaces;
	allspaces = _topology->lookup(allspaces);

	for(int i=0;i<allspaces.size();i++) {
#ifdef DEBUG
		cout << "##################### clean ########################" << endl;
		cout << "service name = " << allspaces[i].getName() << endl;
		cout << "instance name = " << _instance << endl;
		cout << "host ip = " << allspaces[i].getIP() << endl;
		cout << "host port = " << allspaces[i].getPort() << endl;
		cout << "####################################################" << endl;
#endif

		_clean(allspaces[i]);
	}
}
